
#ifndef __KERNEL_H__
#define __KERNEL_H__

#include "basetype.h"
#include "stm32f4xx.h"

#define OS_TYPE_UCOSII		0
#define OS_TYPE_FREERTOS	1
#define OS_TYPE				OS_TYPE_FREERTOS

#ifdef PRINTF
#define KPRINTF				PRINTF
#else
#define KPRINTF(fmt,arg...)
#endif

/*------定义任务默认堆栈大小(实际堆栈大小=STKLEN*4,4为MCU位宽)-------*/
#define TASK_STACK_256B        64
#define TASK_STACK_512B        128
#define TASK_STACK_1024B       256
#define TASK_STACK_1536B       384
#define TASK_STACK_2048B       512
#define TASK_STACK_3072B       768
#define TASK_STACK_4096B       1024

#define IS_IRQ_MASKED()           (__get_PRIMASK() != 0U)
#define IS_IRQ_MODE()             (__get_IPSR() != 0U)
#define IS_IRQ()                  (IS_IRQ_MODE() || IS_IRQ_MASKED())
 
#if (OS_TYPE==OS_TYPE_UCOSII)
#include "ucos_ii.h"
#include "lib_def.h"
#include "port.h"
/******************************************************************************
 * uCOSII任务优先级说明
 * 系统共64个优先级(0~63),数字越小优先级越高
 * 不能使用的8个优先级:
 * 0,1,2,3,OS_LOWEST_PRIO-3,OS_LOWEST_PRIO-2,OS_LOWEST_PRIO-1,OS_LOWEST_PRIO
 * 即:
 * 不能使用的优先级: 0,1,2,3,28,29,30,31
 * 可以使用的优先级: 4~27 共24个
 * 暂时先使用10~25这16个优先级
 *****************************************************************************/
#define KERNEL_NAME                 "uCOSII"
#define KERNEL_VERSION              OS_VERSION          /* V2.9.2 */
#define SYSTEM_TICK_HZ  		    OS_TICKS_PER_SEC	/* 默认为100HZ,OS_TICKS_PER_SEC定义在os_cfg.h */
#define SYSTEM_TICK_MS  		    10 					/* =1000/SYSTEM_TICK_HZ */
#define KERNEL_MUTEX_MAX  		    32					/* 最大可使用的互斥锁个数 */
#define KERNEL_TASK_INIT_PRIO	    25					/* 内核init任务的优先级 */
#define KERNEL_TASK_INIT_STACK      TASK_STACK_1024B	/* 内核init任务堆栈大小 */
typedef uint32 tick_t;
typedef uint32 stack_t;
typedef uint8 task_t;
typedef uint8 prio_t;
typedef uint8 mutex_t;
typedef uint8 msgqueue_t;
typedef uint8 sem_t;

#elif (OS_TYPE==OS_TYPE_FREERTOS)
#include "FreeRTOS.h"
#include "task.h"
/******************************************************************************
 * FreeRTOS任务优先级说明
 * 数值越小，优先级越低，系统idle任务优先级最低(0)
 *****************************************************************************/
#define KERNEL_NAME                 "FreeRTOS"
#define KERNEL_VERSION              ((tskKERNEL_VERSION_MAJOR*100)+(tskKERNEL_VERSION_MINOR*10)+tskKERNEL_VERSION_BUILD)
#define SYSTEM_TICK_HZ  		    configTICK_RATE_HZ	/* 默认为1000HZ */
#define SYSTEM_TICK_MS  		    1 					/* =1000/SYSTEM_TICK_HZ */
#define KERNEL_TASK_INIT_PRIO	    1					/* 内核init任务的优先级 */
#define KERNEL_TASK_INIT_STACK      TASK_STACK_512B		/* 内核init任务堆栈大小 */

typedef uint32 tick_t;
typedef uint32 stack_t;
typedef uint32 task_t;
typedef uint8 prio_t;
typedef uint32 mutex_t;
typedef uint32 msgqueue_t;
typedef uint32 sem_t;

/**
 * @brief 发送任务通知
 * @param taskID 
 * @param inISR 是否在中断中
 * @return true 
 * @return false 
 */
bool kernel_notify_send(task_t taskID);

/**
 * @brief 获取任务通知值
 * @param msTimeout 
 * @return uint32 
 * @note FreeRTOS只允许一个任务接收通知
 */
uint32 kernel_notify_recv(sint32 msTimeout);
#else
#error "not define OS_TYPE!"
#endif

typedef void (*func_kernel_init)(void);

/**
 * @brief 内核初始化(会启动第一个任务,在这个任务中会调用init函数)
 * @param init init函数
 */
void kernel_init(func_kernel_init init);

/**
 * @brief 内核启动(进入任务调度)
 */
void kernel_start(void);

/**
 * @brief 获取内核配置的系统时钟
 * @return uint32 
 */
uint32 kernel_sysclk(void);

/**
 * @brief 创建任务
 * @param task 任务函数
 * @param name 任务名称
 * @param prio 优先级
 * @param stkSize 任务堆栈大小
 * @param attr 属性(视RTOS而定,可自定义,ucosII中属性值为任务栈地址)
 * @return task_t 
 */
task_t kernel_task_create(void(*task)(void*),const char* name, prio_t prio, int stkSize,void* attr);

/**
 * @brief 取消任务
 * @param taskID 
 */
void kernel_task_cancel(task_t taskID);

/**
 * @brief 打印任务信息
 * @param taskID 
 */
void kernel_task_info(task_t taskID);

/**
 * @brief 动态申请内存
 * @param size 内存大小
 * @return void* 
 */
void* kernel_malloc(uint32 size);

/**
 * @brief 释放动态内存
 * @param mem 
 */
void kernel_free(void* mem);

/**
 * @brief 内核休眠(会触发任务切换)
 * @param ticks 系统滴答数
 */
void kernel_sleep(tick_t ticks);

/**
 * @brief 获取内核时间(系统启动到当前过去的滴答数)
 * @return tick_t 
 */
tick_t kernel_gettime(void);

/**
 * @brief 进入临界区
 */
void kernel_critical_enter(void);

/**
 * @brief 退出临界区
 */
void kernel_critical_exit(void);

/**
 * @brief 创建互斥锁
 * @return mutex_t 
 * @note 互斥锁不允许在中断中使用
 */
mutex_t kernel_mutex_init(void);

/**
 * @brief 互斥锁上锁
 * @param mutex 
 */
void kernel_mutex_lock(mutex_t mutex);

/**
 * @brief 互斥锁解锁
 * @param mutex 
 */
void kernel_mutex_unlock(mutex_t mutex);

/**
 * @brief 创建消息队列
 * @param mqSize 最大容纳的消息数
 * @param msgSize 消息长度
 * @return msgqueue_t 
 */
msgqueue_t kernel_mq_init(uint32 mqSize, uint32 msgSize);

/**
 * @brief 发送消息
 * @param mq 消息队列
 * @param msg 消息
 * @param msTimeout 超时时间(在中断中调用时忽略该参数;-1:阻塞;0:不阻塞)
 * @return true 
 * @return false 
 */
bool kernel_mq_send(msgqueue_t mq, void* msg, sint32 msTimeout);

/**
 * @brief 接收消息
 * @param mq 消息队列
 * @param msg 消息
 * @param msTimeout 超时时间(在中断中调用时忽略该参数;-1:阻塞;0:不阻塞)
 * @return true 
 * @return false 
 */
bool kernel_mq_recv(msgqueue_t mq, void* msg, sint32 msTimeout);

/**
 * @brief 获取消息队列大小(消息个数)
 * @param mq 
 * @return uint32 
 */
uint32 kernel_mq_size(msgqueue_t mq);

/**
 * @brief 创建信号量 
 * @param max 信号量最大值(设为0时表示创建二值信号量)
 * @return sem_t 
 * @note 二值信号量类似于Mutex,区别是二值信号量可以在中断中使用
 */
sem_t kernel_sem_init(uint32 max);

/**
 * @brief 发送信号量
 * @param sem 
 * @param msTimeout 超时时间(-1:阻塞,0:不阻塞)
 * @return true 
 * @return false 
 */
bool kernel_sem_post(sem_t sem, sint32 msTimeout);

/**
 * @brief 等待信号量
 * @param sem 
 * @param msTimeout msTimeout 超时时间(在中断中调用时忽略该参数;-1:阻塞;0:不阻塞)
 * @return true 
 * @return false 
 */
bool kernel_sem_wait(sem_t sem, sint32 msTimeout);

#endif

